#include "InputWatcher.h"

#include <stdlib.h>

#include "worker-monitor-topics.h"
#include "SatelliteInterface.h"
//TODO: comments
Gui* InputWatcher::singleton = 0;
const int InputWatcher::lineInput = 19;
const int InputWatcher::INPUTSIZE=9;

InputWatcher::InputWatcher(){}
InputWatcher::~InputWatcher() {}

void InputWatcher::init() {
	//initializes the global variables
	input =new char[INPUTSIZE];
	for(int j=0;j<INPUTSIZE;j++) input[j]='\0';
	i=0;
	singleton = Gui::getSingletonPtr();
}


void InputWatcher::run() {
	//initialising the two needed booleans
	bool reading=true;
	bool stop=false;
	while(1) {
		//setting up a TIME_LOOP
		TIME_LOOP(NOW(),20*MILLISECONDS){
			//move coursor to input line, behind the already done input
			PRINTF(SCREEN_MOVE_CURSOR_TO,lineInput,i+1);
			//going on if the input isnt to big or ended by entering Enter
			if(reading){
				stop=false;
				//remains doing the following until either the input is complete, to big
				//or the last read character wasn't valid
				while(isCharReady()&&reading&&!stop){
					//reading char from consoleInput
					char buff= getcharNoWait();
					//setting reading to false, if the read character was '\n’
					if(buff=='\n') {
						reading=false;
					}
					//adding the read character to the input, if it is valid
					else if((buff>='0'&&buff<='9') || (buff>='a'&&buff<='z') || (buff>='A'&&buff<='Z'))
					{
						input[i++]=buff;
					}else if((buff==8 || buff==127) && i>0){ //checking if the input was backspace
						input[--i]='\0';		//resets the last input and decreases i by 1
					}else {
						//sets stop to true to stop this loop, after reading a nonvalid character
						stop=true;
					}


					if(i>=INPUTSIZE) //setting reading to false, if the input is to long
						reading=false;
				}
				//sets the variable consoleInput in the Gui to input
				singleton->setConsoleInput(input);
			}

			//if the reading is complete, the input has to be handled
			if(!reading){
				//sets the InfoMessage to display the latest done input
				singleton->setInfoMessage(input);
				//calls the function handleInput() to handle the input
				handleInput();
				//reseting the variables to their initialisation value
				for(int j=0;j<INPUTSIZE;j++) input[j]='\0';
				i=0;
				reading=true;
				singleton->setConsoleInput(input);
				//tells the Gui top refresh itself
				singleton->refresh();
			}
		}
	}
}

void InputWatcher::handleInput(){
	//boolean to check, if a valid Command was entered
	bool unknownCommand=false;
	//switching to the length of the input
	//and then iterating through all possible valid commands
	//If the command was found, the Replyline gets a suitable text and the matching functions get called
	switch(i){
	case 1:
		if(input[0]=='p') {
			singleton->setReply("Send: PING!");
			//Not used because ping is called every second automatically
			//satelliteInterface.Ping();
		}
		else if(input[0]=='i') {
			singleton->setReply("Toggled Info");
			singleton->setToggleInfo();
		}
		else if(input[0]=='u') {
			singleton->setReply("updated satellite");
			satelliteInterface.updateSatellite();
		}
		else
			unknownCommand=true;
		break;
	case 2:
		if( (input[0]=='g') && (input[1]=='w')){
			int ID=satelliteInterface.getWorkerID();
			if(ID==0) singleton->setReply("Worker Fault: Didnt receive valid WorkerID in time");
			else	singleton->setReply(intToStr("Worker ID: ",ID).c_str());
		}
		else if( (input[0]=='g') && (input[1]=='m')){
			operationMode temp=satelliteInterface.getMode();
			if(temp==NORMAL)	singleton->setReply("satellite works in NORMAL-mode");
			else singleton->setReply("no mode received");
			}
		else if( (input[0]=='s') && (input[1]=='w'))
			singleton->setReply("Missing Argument: ID of Node to become Worker");
		else if( (input[0]=='s') && (input[1]=='m'))
			singleton->setReply("Missing Argument: Mode to switch into");
		else if( (input[0]=='s') && (input[1]=='p'))
			singleton->setReply("Missing Argument: boolean t:true or f:false to set publishing");

		else unknownCommand=true;
		break;
	case 3:
		if( input[0]=='s' && input[1]=='w' ){
				if(47<input[2] && input[2]<58){
					//checking the existance of the Node to become Worker
					if(satelliteInterface.existNode(input[2]-48)){
						singleton->setReply(intToStr("set Worker to: ",input[2]-48).c_str());
						satelliteInterface.setWorker(input[2]-48);}
					else singleton->setReply(intToStr("Invalid Node Number : it doesnt exist a Node with the ID ",input[2]-48).c_str());
				}
			else singleton->setReply("Invalid Argument: 3rd Argument must be a digit");
		}
		else if( input[0]=='s' && input[1]=='m'){
			//Iteration threw all possible mode-shortcuts (yet just: n:Normal)
			if(input[2]=='n'){
				singleton->setReply("Mode set to: NORMAL");
				satelliteInterface.setMode(NORMAL);}
			else singleton->setReply("Invalid Argument: 3rd Argument must be a regular Mode\nn:normal ...");
		}
		else if(input[0]=='s' && input[1]=='p'){
			if(input[2]=='t'){
				singleton->setReply("set publishing to: true");
				satelliteInterface.setPublishStatusData(true);
			}
			else if(input[2]=='f'){
				singleton->setReply("set publishing to: false");
				satelliteInterface.setPublishStatusData(false);
			}
			else singleton->setReply("Invalid Argument: 3rd Argument must be either 't' : true or 'f' : false");
		}
		else if(input[0]=='s'&&input[1]=='s'&&input[2]=='p'){
			singleton->setReply("Missing Argument: Time in ms to set Status Period to");
		}
		else unknownCommand=true;
		break;
	case 4:
	case 5:
	case 6:
	case 7:
	case 8:
	case 9:
		if(input[0]=='s'&&input[1]=='s'&&input[2]=='p')
		{	long num=0;
			bool allNum=true;
			for(int j=3;j<i;j++)
			{
				if(47<input[j]&&input[j]<58)
					num=num*10+(input[j]-48);
				else allNum=false;
			}
			if(num==0) singleton->setReply("Invalid Argument: status period cannot be set to 0");
			else	if(!allNum) singleton->setReply("Invalid Argument: One or more spots contains non-digit Argument");
				else{
						singleton->setReply((intToStr("Status period set to: ",num)+"ms").c_str());
						satelliteInterface.setPublishPeriod(num);
				}
		}
		break;
	default: unknownCommand=true;break;
	}
	//if no matching input was found, an unknown command message is being printed
	if(unknownCommand) singleton->setReply("Unknown command, type i to check valid commands");
	//singleton->refresh();

}
//this function converts an int variable into a string which is added at the end of the parsed msg and retuns it
string InputWatcher::intToStr(const char* msg,int num){

	std::string s;
	std::stringstream out;
	out << num;
	s = out.str();
	s=msg+s;
	return s;
}
